
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.BorderLayout;

import javax.swing.JPanel;
import javax.swing.JLabel;
import java.awt.event.*;

import com.jchy.renderit.core.Camera;
import com.jchy.renderit.core.Dir;
import com.jchy.renderit.core.Displayable;
import com.jchy.renderit.core.Light;
import com.jchy.renderit.core.MyInput;
import com.jchy.renderit.core.Point;
import com.jchy.renderit.core.Hit;
import com.jchy.renderit.core.Scene;
import com.jchy.renderit.core.RenderEngine;
import com.jchy.renderit.core.PropertiesAndMethods;
import com.jchy.renderit.displayable.BilliardStripe;
import com.jchy.renderit.displayable.Checked;
import com.jchy.renderit.displayable.Circle;
import com.jchy.renderit.displayable.Cube;
import com.jchy.renderit.displayable.Cylinder;
import com.jchy.renderit.displayable.Lens;
import com.jchy.renderit.displayable.Octahedron;
import com.jchy.renderit.displayable.Plane;
import com.jchy.renderit.displayable.Sphere;
import com.jchy.renderit.displayable.Tetrahedron;
import com.jchy.renderit.displayable.Triangle;

public class StereoRectPanel extends JPanel implements ActionListener, MouseMotionListener {

    private Scene scene;
    private Camera view1,  view2;
    private RenderEngine render1,  render2;
    private static final long serialVersionUID = 999;
    private Point prp1;
    private Point prp2;
    private int xMin,  xMax,  yMin,  yMax;
    private Point lookat;
    private double invZoom;
    private BorderLayout bl;
    private JLabel tip;

    public StereoRectPanel(){


        bl = new BorderLayout();
        setLayout(bl);
        tip = new JLabel();
        add(tip, BorderLayout.SOUTH);
        addMouseMotionListener(this);

        scene = new Scene();
        view1 = new Camera();
        view2 = new Camera();

        addSceneObjects();

        addLights();

        setView();

        xMin = 0;
        xMax = 200;
        yMin = 0;
        yMax = 200;

        render1 = new RenderEngine(scene, view1, xMax, yMax);

        render1.render();

        render2 = new RenderEngine(scene, view2, xMax, yMax);

        render2.render();

    }

    public void setView() {
        view1.setDown(new Dir(0, 1, 0));
        view1.setInvZoom(0.5);
        view1.setLookat(new Point(0, 0, -100));
        view1.setPrp(new Point(-30, 0, -300));
        view1.setupView();

        view2.setDown(new Dir(0, 1, 0));
        view2.setInvZoom(0.5);
        view2.setLookat(new Point(0, 0, -100));
        view2.setPrp(new Point(30, 0, -300));
        view2.setupView();

    }

    public void addLights() {
        Light aLight = new Light();
        aLight.location.x = 0;
        aLight.location.y = -1000;
        aLight.location.z = -700;
        aLight.color = new Color(255, 255, 255);

        scene.addLight(aLight);
    }

    public void addSceneObjects() {

        BilliardStripe abs = new BilliardStripe();
        abs.scale(75, 75, 75);
        abs.RotateY(30.0);
        abs.SetShading(0.2, 0.8, 0.01, 4);
        scene.addDisplayable(abs);

        Sphere sph = new Sphere();
        sph.scale(20, 20, 20);
        sph.setPrimaryColorInt(Color.BLUE.getRed(), Color.BLUE.getGreen(), Color.BLUE.getBlue());
        sph.translate(0.0, 0.0, -100.0);
        scene.addDisplayable(sph);

        Octahedron oct = new Octahedron();
        oct.scale(20, 20, 20);
        oct.RotateX(20.0);
        oct.setPrimaryColorInt(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue());
        oct.translate(-70.0, -70.0, -70.0);
        scene.addDisplayable(oct);

        Checked chk = new Checked();
        chk.scale(50, 50, 50);
        chk.translate(0, 0, 200);
        scene.addDisplayable(chk);

    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);

        boolean result;

        result = g.drawImage(render1.getImage(), xMin, yMin, this);

        result = g.drawImage(render2.getImage(), xMax, yMin, this);

    } // paintcomponent

    public void actionPerformed(ActionEvent e) {

        render1.render();
        render2.render();

        this.repaint();
    }

    public void runMainMenu() {
        String mainMenu;
        String addType;
        String updtType;
        String updateThis;
        String delType;
        String deleteThis;
        Light aLight;
        Displayable aDisplayable;
        Camera aCamera;
        int pos;

        main_menu:
        do {
            aDisplayable = null;
            aLight = null;
            aCamera = null;
            pos = -1;
            addType = "";
            updtType = "";
            delType = "";
            deleteThis = "";
            System.out.print("(A)dd (U)pdate (D)elete (X)Exit: ");
            mainMenu = MyInput.readString();
            if (mainMenu.equals("a")) {
                System.out.print("(L)ight (D)isplayable (X)Exit: ");
                addType = MyInput.readString();
                if (addType.equals("l")) {
                    aLight = new Light();
                } // Add Light
                else if (addType.equals("d")) {
                    System.out.println("(P)lane (H)Checked (T)riangle (C)ircle ");
                    System.out.println("(S)phere (Y)Cylinder (B)BilliardStripe (L)ens ");
                    System.out.print("(U)Cube (R)Tetrahedron (O)ctahedron (X)Exit: ");
                    String dispType = MyInput.readString();
                    if (dispType.equals("p")) {
                        aDisplayable = new Plane();
                    } else if (dispType.equals("h")) {
                        aDisplayable = new Checked();
                    } else if (dispType.equals("t")) {
                        aDisplayable = new Triangle();
                    } else if (dispType.equals("c")) {
                        aDisplayable = new Circle();
                    } else if (dispType.equals("s")) {
                        aDisplayable = new Sphere();
                    } else if (dispType.equals("y")) {
                        aDisplayable = new Cylinder();
                    } else if (dispType.equals("b")) {
                        aDisplayable = new BilliardStripe();
                    } else if (dispType.equals("l")) {
                        aDisplayable = new Lens();
                    } else if (dispType.equals("u")) {
                        aDisplayable = new Cube();
                    } else if (dispType.equals("r")) {
                        aDisplayable = new Tetrahedron();
                    } else if (dispType.equals("o")) {
                        aDisplayable = new Octahedron();
                    } else {
                        continue main_menu;
                    }

                } // Add Displayable
                else {
                    continue main_menu;
                }

            } // Add
            else if (mainMenu.equals("u")) {
                System.out.print("(L)ight (D)isplayable (V)iew (X)Exit: ");
                updtType = MyInput.readString();
                if (updtType.equals("v")) {
                    updtview:
                    for (int i = 0; i < 2; i++) {
                        if (i == 0) {
                            System.out.println(view1.getClass().getName());
                            System.out.println(view1);
                        } else if (i == 1) {
                            System.out.println(view2.getClass().getName());
                            System.out.println(view2);
                        }

                        System.out.print("Update this object? ");
                        updateThis = MyInput.readString();
                        if (updateThis.equals("y")) {
                            if (i == 0) {
                                aCamera = view1;
                            } else if (i == 1) {
                                aCamera = view2;
                            }
                            pos = i;
                            break updtview;
                        }
                    }
                } else if (updtType.equals("l")) {
                    updtlight:
                    for (int i = 0; i < scene.getLightCount(); i++) {
                        System.out.println(scene.getLight(i).getClass().getName());
                        System.out.println(scene.getLight(i));
                        System.out.print("Update this object? ");
                        updateThis = MyInput.readString();
                        if (updateThis.equals("y")) {
                            aLight = scene.getLight(i);
                            pos = i;
                            break updtlight;
                        }
                    } // traverse lights

                    if (aLight == null) {
                        continue main_menu;
                    }

                } // Update Light
                else if (updtType.equals("d")) {
                    updtdisp:
                    for (int i = 0; i < scene.getDisplayableCount(); i++) {
                        System.out.println(scene.getDisplayable(i).getClass().getName());
                        System.out.println(scene.getDisplayable(i));
                        System.out.print("Update this object? ");
                        updateThis = MyInput.readString();
                        if (updateThis.equals("y")) {
                            aDisplayable = scene.getDisplayable(i);
                            pos = i;
                            break updtdisp;
                        }
                    } // traverse scene
                    if (aDisplayable == null) {
                        continue main_menu;
                    }

                } // Update Displayable
                else {
                    continue main_menu;
                }

            } // Update
            else if (mainMenu.equals("d")) {
                System.out.print("(L)ight (D)isplayable (X)Exit: ");
                delType = MyInput.readString();
                if (delType.equals("l")) {
                    dellight:
                    for (int i = 0; i < scene.getLightCount(); i++) {
                        System.out.println(scene.getLight(i));
                        System.out.print("Delete this object? ");
                        deleteThis = MyInput.readString();
                        if (deleteThis.equals("y")) {
                            aLight = scene.getLight(i);
                            pos = i;
                            break dellight;
                        }
                    } // traverse lights

                    if (aLight == null) {
                        continue main_menu;
                    }

                } // Delete Light
                else if (delType.equals("d")) {
                    deldisp:
                    for (int i = 0; i < scene.getDisplayableCount(); i++) {
                        System.out.println(scene.getDisplayable(i).getClass().getName());
                        System.out.println(scene.getDisplayable(i));
                        System.out.print("Delete this object? ");
                        deleteThis = MyInput.readString();
                        if (deleteThis.equals("y")) {
                            aDisplayable = scene.getDisplayable(i);
                            pos = i;
                            break deldisp;
                        }
                    } // traverse scene
                    if (aDisplayable == null) {
                        continue main_menu;
                    }

                } // Delete Displayable
                else {
                    continue main_menu;
                }

            } // Delete
            else {
                break main_menu;
            }

            String done = "";
            if (!mainMenu.equals("d")) {
                do {
                    if (updtType.equals("l")) {
                        PropertiesAndMethods.prompt(aLight);
                    } else if (updtType.equals("d")) {
                        PropertiesAndMethods.prompt(aDisplayable);
                    }
                    System.out.print("Are you done with this object? ");
                    done = MyInput.readString();
                } while (!done.equals("y"));
            }

            if (mainMenu.equals("u") || mainMenu.equals("d")) {
                if (updtType.equals("l")) {
                    scene.removeLight(pos);
                } else if (updtType.equals("d")) {
                    scene.removeDisplayable(pos);
                }

                if (delType.equals("l")) {
                    scene.removeLight(pos);
                } else if (delType.equals("d")) {
                    scene.removeDisplayable(pos);
                }
            } // Update or Delete (then delete the object)

            if (mainMenu.equals("a") || mainMenu.equals("u")) {
                if (addType.equals("l")) {
                    scene.addLight(aLight);
                } else if (addType.equals("d")) {
                    scene.addDisplayable(aDisplayable);
                }

                if (updtType.equals("l")) {
                    scene.addLight(aLight);
                } else if (updtType.equals("d")) {
                    scene.addDisplayable(aDisplayable);
                }
            } // Add or Update (then add the object)

            if (mainMenu.equals("u") && updtType.equals("v")) {
                if (pos == 0) {
                    view1 = (Camera) aCamera;
                } else if (pos == 1) {
                    view2 = (Camera) aCamera;
                }

            }

        } while (!mainMenu.equals("x"));

    }

    public void mouseDragged(MouseEvent e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseMoved(MouseEvent e) {

        Hit aHit;

        aHit = new Hit();

        if((e.getX() > xMin) && (e.getX() < xMax) && (e.getY() > yMin) && (e.getY() < yMax)) {

            aHit = render1.getHit(e.getX(), e.getY());

        }

        if((e.getX() > xMax) && (e.getX() < (2 * xMax)) && (e.getY() > yMin) && (e.getY() < yMax)) {

            aHit = render2.getHit(e.getX() - xMax, e.getY());

        }

        if(aHit.isHit)
            tip.setText(aHit.getTarget().getClass().getName());
        else tip.setText("");

    }


}
